<?php
namespace app\api\validate;
use think\Validate;
use think\Request;
use think\Db;
class BaseValidate extends Validate
{

     /**
     * 检测所有客户端发来的参数是否符合验证类规则
     * 基类定义了很多自定义验证方法
     * 这些自定义验证方法其实，也可以直接调用
     * @param validate 类中的验证方法
     * @return true
     */
    public function LoginCheck($rule)
    {

        // 必须设置contetn-type:application/json
        $request = Request::instance();
        $params = $request->post();

        if (!$this->check($params,$this->$rule)){
             $this->show_error($this->error,305);
        }

        return true;

    }

    /**
     * 检测所有客户端发来的参数是否符合验证类规则
     * 基类定义了很多自定义验证方法
     * 这些自定义验证方法其实，也可以直接调用
     * @param validate 类中的验证方法
     * @return true
     */
    public function goCheck($rule)
    {

        // 必须设置contetn-type:application/json
        $request = Request::instance();
        $params = $request->post();
        $header = Request::instance()->header();
        // p($header);
        //验证access_token
        $this->AccessTokenCheck($request->header('token'));
        // //验证请求时间 timestamp
        $this->checkTime($request->header('timestamp'));
        //验证签名
        $this->checkSign($request->header('sign'),$params);

        if (!$this->check($params,$this->$rule)){
             $this->show_error($this->error,302);
        }

        return true;

    }
    //验证access_token
    public function AccessTokenCheck($token){

        if(empty($token)){
            $this->show_error('token不能为空!',301);
        }

        $info=Db::table('cms_user')->cache(true)->where(array('access_token'=>$token,'overdue_date'=>array('gt',date('Y-m-d H:i:s'))))->fetchSql(false)->field('id,access_token,overdue_date,refresh_token')->find();

        if(!$info){
            $this->show_error('无效的token 或已超出有效时间!',301);
        }

    }

    //验证签名
    protected   function checkSign($sign,$params=array()){

        //服务端生成签名与客户端验证
        $servicesign=$this->servicesign($params);
        // echo 'servicesign: '.$servicesign;
        if($sign!=$servicesign){
            $this->show_error('sign错误!',304);
        }
    }

    /**
     * 检测时间+_300秒内请求会异常
     */
    public function checkTime($timestamp)
    {
        $time = $timestamp;
        if($time > time()+200  || $time < time()-200){
            return $this->show_error(401,'请求的时间不正确!');
        }
    }
    /**
     * 显示错误，并中断程序执行
     * @param string $des 错误描述
     */
    protected static function show_error($msg,$code=300) {
        $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
        if(in_array($origin, config('domain'))){
            header("Access-Control-Allow-Origin: ".$origin);
            header("Access-Control-Allow-Methods: GET, POST");
            header("Access-Control-Allow-Headers:Authorization,DNT,OPTIONS,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type, Accept-Language, Origin, Accept-Encoding,token,sign,timestamp");
        }
        header("Content-Type: text/html; charset=utf-8");
        $arr=array(
            'status'    =>      'error',
            'msg'       =>       $msg,
            'code'      =>       $code
        );
        echo json_encode($arr, JSON_UNESCAPED_UNICODE);
        exit();
    }

    //获取签名
    // 必填参数序列化按照key=value&key=value+key后md5加密转换小写。注：参数值为空不加入签名序列
    protected function servicesign($data=array()){
        $str='';
        foreach($data as $k=>$v){
            if($v===null||$v===''){
                unset($data[$k]);
            }
        }
        ksort($data);
        foreach($data as $key =>$value){
            $str.=$key.'='.$value.'&';
        }
        $sign=$str.config("ACCESS");
        // p($sign);
        $sign=strtolower(MD5($sign));
        return $sign;
     }
}